package com.soms.util;

import java.sql.*;
import java.util.Properties;

/**
 * MySQL数据库工具类
 */
public class DBUtil {
    /**
     * MySQL驱动的全路径类名
     */
    public static final String DRIVER;
    /**
     * 连接MySQL的url
     */
    public static final String URL;
    /**
     * 连接MySQL的用户名
     */
    public static final String USERNAME;
    /**
     * 连接MySQL的密码
     */
    public static final String PASSWORD;

    /* 静态域/静态代码块：Java(主程序/tomcat)启动后，优先执行的部分 */
    static {
        Properties properties = PropertiesUtil.getProperties("db.properties");
        DRIVER = properties.getProperty("driver");
        URL = properties.getProperty("url");
        USERNAME = properties.getProperty("username");
        PASSWORD = properties.getProperty("password");
    }

    /**
     * 公共全局的配置获取一个数据库连接
     * @return 数据库连接
     */
    public static Connection getConnection() {
        return getConnection(DRIVER, URL, USERNAME, PASSWORD);
    }

    /**
     * 获取一个数据库连接
     * @param driver MySQL驱动的全路径类名
     * @param url 连接MySQL的url
     * @param username 连接MySQL的用户名
     * @param password 连接MySQL的密码
     * @return 数据库连接
     */
    public static Connection getConnection(String driver, String url, String username, String password) {
        Connection connection = null;
        try {
            // 通过反射加载驱动类
            Class.forName(driver);
            // 获取连接
            connection = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            System.out.println("获取连接失败");
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 获取预编译SQL的公共方法
     * @param connection 数据库连接
     * @param sql 带有?占位符的SQL语句
     * @param params params 匹配?占位符的参数数组
     * @return 预编译的SQL执行器
     * @throws SQLException SQL语法结构错误，抛出SQL异常
     */
    public static PreparedStatement getPreparedStatement(Connection connection, String sql, Object[] params) throws SQLException {
        // 通过连接获取预编译的SQL执行器
        PreparedStatement statement = connection.prepareStatement(sql);
        // 获取SQL语句中的?占位符个数
        int parameterCount = statement.getParameterMetaData().getParameterCount();
        // 为?占位符参数赋值
        if (parameterCount > 0 && params != null && params.length == parameterCount) {
            for (int i = 0; i < params.length; i++) {
                statement.setObject(i + 1, params[i]);
            }
        }
        return statement;
    }

    /**
     * 公共的执行方法：增加/修改/删除
     * @param connection 数据库连接
     * @param sql 带有?占位符的SQL语句
     * @param params 匹配?占位符的参数数组
     * @return 执行结果，1为成功，0为失败
     * @throws SQLException SQL语法结构错误，抛出SQL异常
     */
    public static int execute(Connection connection, String sql, Object[] params) throws SQLException {
        // 定义SQL执行器
        PreparedStatement preparedStatement = null;
        // 定义执行结果
        int result = 0;
        try {
            // 通过连接获取预编译的SQL执行器
            preparedStatement = getPreparedStatement(connection, sql, params);
            // 执行增删改
            result = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            System.out.println("SQL异常");
            // 这里抛异常是为了区分执行失败的原因是SQL语法结构错误还是数据错误
            // SQL语法结构错误会抛出异常，在上一层进行处理
            // 数据错误会导致执行失败，但不会抛出异常，返回结果为0
            throw e;
        } finally {
            closeStatement(preparedStatement);
        }
        return result;
    }

    /**
     * 关闭ResultSet
     * @param resultSet 结果集
     */
    private static void closeResultSet(ResultSet resultSet) {
        System.out.println("关闭结果集");
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭Statement
     * @param statement SQL执行器，包含子类型预编译的SQL执行器
     */
    private static void closeStatement(Statement statement) {
        System.out.println("关闭SQL执行器");
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭ResultSet和Statement
     * @param resultSet 结果集
     * @param statement SQL执行器，包含子类型预编译的SQL执行器
     */
    public static void closeResource(ResultSet resultSet, Statement statement) {
        closeResultSet(resultSet);
        closeStatement(statement);
    }

    /**
     * 关闭Connection
     * @param connection 数据库连接
     */
    public static void closeConnection(Connection connection) {
        System.out.println("关闭连接");
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}